import React from 'react';

import SearchInput from "../../components/SearchInput";

import { NavBar, Icon, PickerView, Toast } from "antd-mobile";

import css from "./index.module.scss";

import { request } from "../../utils/request";

// 引入封装的单个房源展示组件
import HouseItem from "../../components/HouseItem";

// 导入虚拟列表(长列表)插件
import { List } from "react-virtualized";

import { connect } from "react-redux";

/* 
  作业思考：
    1. 当点击筛选条件的时候，应该对 1)房源数组初始化，2)分页参数初始化
    2. 通过 redux 获取城市数据，根据定位城市获取房源数据
*/


class Found extends React.Component {

  // 城市 id，在多个地方使用，所以直接定义到组件上作为自定义数据
  // cityId = '';

  // 筛选选中的参数
  selectParams = {};

  // 是否正在加载数据的标记
  isLoading = false;

  // 准备用于分页的参数，
  pageSize = 20;
  pageParams = {
    // 开始项
    start: 1,
    // 结束项
    end: this.pageSize,
  };

  // 房源列表数据总长度
  houseListCount = 0;

  // state 数据主要用于视图渲染的
  state = {
    filter_title_array: [
      { id: 1, text: '区域', cols: 3 },
      { id: 2, text: '方式', cols: 1 },
      { id: 3, text: '租金', cols: 1 },
      { id: 4, text: '筛选', },
    ],
    // 过滤条件数据
    filter_data: [],
    // 当前选中的状态
    activeIndex: -1,
    // 用户选中的数据，准备一个二维数组结构(这里这样初始化的目的只是为了方便给大家观察)
    select_data: [[], [], [], []],
    // 房源数组
    house_array: []
  };

  // 组件挂载完毕
  componentDidMount() {
    // 获取当前城市下的房源筛选数据（如北京）
    this.getFilterData();
  }

  // 获取当前城市下的房源筛选数据（如北京）
  //     1. 先获取当前城市的 id 标识
  //     2. 把 id 标识作为参数发送换取城市房源数据
  getFilterData = async () => {
    // 过滤条件数据
    let filter_data = [];
    // 1. 先获取当前城市的 id 标识;
    // this.cityId = (await request.get('/area/info?name=')).data.body.value;
    // 2. 获取当前城市下的房源筛选数据
    const res = (await request.get('/houses/condition?id=' + this.props.cityId)).data.body;

    // 第一份数据 - 区域，地铁
    filter_data[0] = [res.area, res.subway];

    // 第二份数据 - 方式 - 整租 合租
    filter_data[1] = res.rentType;

    // 第三份数据 - 价格
    filter_data[2] = res.price;

    // 第四份数据 - 用于右侧展示
    filter_data[3] = [
      { title: '户型', data: res.roomType },
      { title: '朝向', data: res.oriented },
      { title: '楼层', data: res.floor },
      { title: '房屋亮点', data: res.characteristic },
    ];
    // 更新组件状态
    this.setState({ filter_data });
    // 主动获取一次房源数据
    this.gethouseList();
  };

  // 获取 PickerView 值
  pickerViewOnChange = (value) => {
    // 解构
    const { select_data, activeIndex } = this.state;
    // 把第几个 PickerView 数据保存到数组第几项
    select_data[activeIndex] = value;
    // 更新状态
    this.setState({ select_data });
  };

  /* 
    更多筛选条件
      1. 点击能选中，把 value 值添加到数组中
      2. 再点击就不选中，把 value 值从数组中删除(索引值)
  */
  getSelectMore = (value) => {
    // 解构
    const { select_data, activeIndex } = this.state;
    // 通过 findIndex 查到 value 是否存在于数组中
    //   1. 不存在返回 -1，走添加操作
    //   2. 存在返回索引值，走删除操作
    const index = select_data[activeIndex].findIndex(item => item === value);
    if (index === -1) {
      select_data[activeIndex].push(value);
    } else {
      select_data[activeIndex].splice(index, 1);
    }
    // 更新状态
    this.setState({ select_data });
  };

  // 获取 PickerView 数据并处理数据格式
  getSelectParams = () => {

    // 清空原本的房源数据
    this.setState({ house_array: [] });
    // 初始化页码  start  end
    this.pageParams.start = 1;
    this.pageParams.end = this.pageSize;

    // 结构选中的数组格式数据 - 不能直接用于请求
    const { select_data } = this.state;
    // 创建个新的变量，处理成后端请求的需要的格式
    let selectParams = {};

    // 第一个 PickerView 比较特殊，有三个选项，要处理以下两种情况：
    //  1. 如果三项都选择了，第一项是键名称key，第三项是值 value
    //  2. 如果第三项选择了不限 'null'，第二项才是 value 值
    const key1 = select_data[0][0];
    const value1 = ['null'].includes(select_data[0][2]) ? select_data[0][1] : select_data[0][2];
    selectParams = {
      // 第一个 PickerView 的数据处理成参数
      [key1]: value1,
      // 以下三个键名称需要根据接口文档参数起名
      rentType: select_data[1][0],
      price: select_data[2][0],
      more: select_data[3].join(',')
    };

    // 遍历对象，删除无效的数据
    Object.keys(selectParams).forEach(key => {
      if ([undefined, 'null', ''].includes(selectParams[key])) {
        delete selectParams[key];
      }
    });

    // 隐藏弹出层
    this.hideLayout();
    // 发送请求
    // 把当前的选中的参数，作为当前组件公用数据，用于别处发送请求使用
    this.selectParams = selectParams;

    // 获取房源数据
    this.gethouseList();

    console.log('selectParams', selectParams);
  };

  // 获取房源数据
  gethouseList = async () => {
    // 请求前，把 loading 标记变成真
    this.isLoading = true;
    // 发送请求获取房源数据
    const res = (await request.get('/houses', {
      params: {
        cityId: this.props.cityId,
        ...this.selectParams,
        ...this.pageParams
      }
    })).data.body;
    // 请求完成后，把 loading 标记变成假
    this.isLoading = false;
    // 把房源的总条数保存起来
    this.houseListCount = res.count;
    // 把请求得到的数据，连接到原数组中
    this.setState({ house_array: [...this.state.house_array, ...res.list] });
  };

  // 虚拟长列表渲染行的函数
  rowRenderer = ({ index, key, style }) => {
    // 这里的返回的代码已经会重复渲染了，这里就类似于之前写的 house_array.map 返回的 JSX，第一次渲染无需自己再写 map 了
    return <div key={key} style={style}>
      <HouseItem item={this.state.house_array[index]} />
    </div>;
  };

  // 长列表的滚动事件
  //    scrollHeight    长列表内容总高
  //    clientHeight    可视区高
  //    scrollTop       滚动出去了多少

  // 还没开始滚动的时候，onScroll 自己触发了一次
  onScroll = ({ scrollHeight, clientHeight, scrollTop }) => {
    // 第一次渲染 List 组件的时候，数据还没请求回来，所以列表高度为 0
    // 这行代码思考下是否有问题，如何写更好 ???
    const isFirstRender = scrollHeight === 0;
    // 是否准备触底，大的的高度 - 两个小高度 <= 某个数
    const isReachBottom = scrollHeight - clientHeight - scrollTop <= 60;
    // 是否还有更多的数据
    const isHasMore = this.state.house_array.length < this.houseListCount;

    // 有几种情况是不需要继续往后执行加载分页数据代码的：
    //    1. List 组件首次渲染
    //    2. 还没触底的情况
    //    3. 如果数据还在加载的时候
    //    4. 如果数组的长度已经和 count 一样了
    if (isFirstRender || !isReachBottom || this.isLoading || !isHasMore) {
      // !isHasMore && Toast.info('没有更多数据了', 1);
      return;
    };

    console.log('滚动准备触底了，开始加载下一页数据');
    // 自己处理分页的开始项和结束项
    this.pageParams.start += this.pageSize;
    this.pageParams.end += this.pageSize;
    // 重新请求房源列表数据
    this.gethouseList();
  };

  // 隐藏弹出层
  //    1. 点击遮罩层隐藏
  //    2. 点击取消按钮隐藏
  //    3. 点击确定获取数据后隐藏
  hideLayout = () => {
    // 隐藏弹出的盒子
    this.setState({ activeIndex: -1 });
  };

  // 清除右侧更多筛选的数据
  clearMoreData = () => {
    const { select_data, activeIndex } = this.state;
    // console.log(select_data[activeIndex]);
    // 清空数组，其实就是清空数据
    // select_data[activeIndex] = [];
    // select_data[activeIndex].length = 0;
    select_data[activeIndex].splice(0);
    // 更新状态
    this.setState({ select_data });
  };

  // 抽离出来一个方法，需要实现3个内容展示
  //    1. 展示 123 选项内容
  //    2. 展示 4 选项内容
  //    3. 不展示任何内容
  renderFilterContent() {
    const { activeIndex, filter_title_array, filter_data, select_data } = this.state;
    // 根据当前的索引值，找到对应模块的 id
    const titleId = filter_title_array[activeIndex] ? filter_title_array[activeIndex].id : -1;
    // 根据 id 判断返回哪个模块
    if (titleId >= 1 && titleId <= 3) {
      return <>
        {/* 内容 123 是绝对定位 */}
        <div className={css.filter_content_absolute}>
          {/* 主体123内容 */}
          <div className={css.filter_content_body}>
            {/* PickerView 组件 */}
            <PickerView
              data={filter_data[activeIndex]}
              cols={filter_title_array[activeIndex].cols}
              // 绑定 value 值，受控表单1
              value={select_data[activeIndex]}
              // 绑定 onChange 事件，受控表单2，监听 PickerView 值变化
              onChange={this.pickerViewOnChange}
            />
          </div>
          {/* 底部按钮 */}
          <div className={css.filter_content_footer}>
            <span onClick={this.hideLayout} className={css.filter_content_footer_btn}>取消</span>
            <span
              className={css.filter_content_footer_btn}
              onClick={this.getSelectParams}
            >确定</span>
          </div>
          {/* 遮罩层1 */}
          <div onClick={this.hideLayout} className={css.mask}></div>
        </div>
      </>;
    }
    // 如果 id 等于 4，就显示右侧定位盒子
    else if (titleId === 4) {
      return <>
        {/* 内容4 是 固定定位的盒子 */}
        <div className={css.filter_content4_fixed}>
          {/* 主体4内容 */}
          <div className={css.filter_content4_body}>
            {
              filter_data[3].map(item => (
                <div key={item.title}>
                  {/* 标题 */}
                  <div className={css.title}>{item.title}</div>
                  {/* 列表 */}
                  <div className={css.list}>
                    {
                      item.data.map(item2 => (
                        // 列表每一项
                        <div
                          key={item2.value}
                          // 如果数组中包含当前项的 value 值，就让添加选中的类名
                          className={
                            [
                              css.item,
                              select_data[activeIndex].includes(item2.value) ? css.active : ''
                            ].join(' ')
                          }
                          // 获取当前项的 value 值
                          onClick={() => this.getSelectMore(item2.value)}
                        >
                          {item2.label}
                        </div>
                      ))
                    }
                  </div>
                </div>
              ))
            }
          </div>
          {/* 底部按钮 */}
          <div className={css.filter_content_footer}>
            <span onClick={this.clearMoreData} className={css.filter_content_footer_btn}>清除</span>
            <span onClick={this.getSelectParams} className={css.filter_content_footer_btn}>确定</span>
          </div>
          <div onClick={() => this.setState({ activeIndex: -1 })} className={css.mask}></div>
        </div>
      </>;
    }
    // 其他情况下，返回空标签，相当于不展示内容 
    else {
      return <></>;
    }
  }

  // 改变索引值
  changeIndex = (activeIndex) => {
    if (activeIndex === this.state.activeIndex) return;
    this.setState({ activeIndex });
  };
  render() {
    const { filter_title_array, activeIndex, house_array } = this.state;
    return (
      <div className={css.found}>
        {/* 1.0 顶部导航组件 开始 */}
        <NavBar
          mode="light"
          icon={<Icon type="left" />}
          onLeftClick={() => this.props.history.go(-1)}
        >
          {/* 组件内部再嵌套组件 */}
          <SearchInput></SearchInput>
        </NavBar>
        {/* 1.0 顶部导航组件 结束 */}
        {/* 2.0 信息筛选过滤模块 开始 */}
        <div className={css.filter}>
          {/* 过滤头部 */}
          <div className={css.filter_title}>
            {
              filter_title_array.map((item, index) => (
                <div
                  onClick={() => this.changeIndex(index)}
                  key={item.id}
                  className={
                    [
                      css.filter_title_item,
                      index === activeIndex ? css.active : ''
                    ].join(' ')
                  }
                >
                  <span>{item.text}</span>
                  <i className="iconfont icon-arrow"></i>
                </div>
              ))
            }
          </div>
          {/* 过滤内容展示 - 难点 */}
          <div className={css.filter_content}>
            {/* 调用函数，内部返回所需的 JSX 结构 */}
            {this.renderFilterContent()}
          </div>
        </div>
        {/* 2.0 信息筛选过滤模块 结束 */}
        <div className={css.house_list}>
          {/* 虚拟长列表组件调用：5个必要参数 */}
          <List
            width={window.screen.width}
            height={window.screen.height - 45 - 40 - 50}
            rowCount={house_array.length}
            rowHeight={108}
            rowRenderer={this.rowRenderer}
            // 滚动事件
            onScroll={this.onScroll}
          />
        </div>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  cityId: state.address.cityId
});

export default connect(mapStateToProps)(Found);

